// 给定一个整型数组, 你的任务是找到所有该数组的递增子序列，递增子序列的长度至少是2。

// 示例:

// 输入: [4, 6, 7, 7]
// 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
// 说明:

// 给定数组的长度不会超过15。
// 数组中的整数范围是 [-100,100]。
// 给定数组中可能包含重复数字，相等的数字应该被视为递增的一种情况。

#include <vector>
#include <unordered_set>

using namespace std;

/* 二进制枚举 + 哈希
时间复杂度：O(n * 2^n)
空间复杂度：O(2^n)
*/
class Solution {
private:
    vector<int> temp{};
    vector<vector<int>> res{};
    unordered_set<int> s{};
    int n{};
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        n = nums.size();
        for (int i{0}; i < (1 << n); ++i) {
            findSubsequences(i, nums);
            int hashValue = getHash(263, static_cast<int>(1E9) + 7);
            if (check() && s.find(hashValue) == s.end()) {
                res.push_back(temp);
                s.insert(hashValue);
            }
        }
        return res;
    }
    void findSubsequences(int mask, vector<int>& nums) {
        temp.clear();
        for (int i{0}; i < n; ++i) {
            if (mask & 1) {
                temp.push_back(nums[i]);
            }
            mask >>= 1;
        }
    }
    int getHash(int base, int mod) {
        int hashValue{0};
        for (const auto& x : temp) {
            hashValue = 1LL * hashValue * base % mod + (x + 101);
            hashValue %= mod;
        }
        return hashValue;
    }
    bool check() {
        for (int i{1}; i < temp.size(); ++i) {
            if (temp[i] < temp[i - 1]) {
                return false;
            }
        }
        return temp.size() >= 2;
    }
};

/* 递归枚举 + 剪枝
时间复杂度：O(n * 2^n)
空间复杂度：O(n)
*/
class Solution {
private:
    vector<int> temp{};
    vector<vector<int>> res{};
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        dfs(0, INT_MIN, nums);
        return res;
    }
    void dfs(int cur, int last, vector<int>& nums) {
        if (cur == nums.size()) {
            if (temp.size() >= 2) {
                res.push_back(temp);
            }
            return;
        }
        if (nums[cur] >= last) {
            temp.push_back(nums[cur]);
            dfs(cur + 1, nums[cur], nums);
            temp.pop_back();
        }
        if (nums[cur] != last) {
            dfs(cur + 1, last, nums);
        }
    }
};